#!/usr/local/bin/python3
# -*- coding: utf-8 -*-

"""
@File    : stdf_class.py
@Author  : Link
@Time    : 2021/7/31 13:32
@Mark    : 必须要3.7及以下的python版本, 更高的版本无法顺利载入dll, 本人已经放弃
"""
import ctypes
import os
import itertools
import string
import win32api


class STD_TYPE:
    FAR = 0
    ATR = 1
    MIR = 2
    MRR = 3
    PCR = 4
    HBR = 5
    SBR = 6
    PMR = 7
    PGR = 8
    PLR = 9
    RDR = 10
    SDR = 11
    WIR = 12
    WRR = 13
    WCR = 14
    PIR = 15
    PRR = 16
    TSR = 17
    PTR = 18
    MPR = 19
    FTR = 20
    BPS = 21
    EPS = 22
    GDR = 23
    DTR = 24
    UNKNOWN = 25

    type_dict = {
        0: "FAR",
        1: "ATR",
        2: "MIR",
        3: "MRR",
        4: "PCR",
        5: "HBR",
        6: "SBR",
        7: "PMR",
        8: "PGR",
        9: "PLR",
        10: "RDR",
        11: "SDR",
        12: "WIR",
        13: "WRR",
        14: "WCR",
        15: "PIR",
        16: "PRR",
        17: "TSR",
        18: "PTR",
        19: "MPR",
        20: "FTR",
        21: "BPS",
        22: "EPS",
        23: "GDR",
        24: "DTR",
        25: "UNKNOWN",
    }


class LinkStdf:
    stdf = None
    import_status = False

    STDF_RETURN = {
        0: "STDF_OPERATE_OK",
        -1: "READ_ERROR",
        -2: "FORMAT_ERROR",
        -3: "STDF_CPU_TYPE_NOT_SUPPORT",
        -4: "STDF_VERSION_NOT_SUPPORT",
        -5: "WRITE_ERROR",
    }

    STDF_RESULT = {
        0x8: -1,
        0x0: 1,
        0x7: -1,
        0x6: -1,
        0x5: 0,
        0x4: -1,
    }

    def __init__(self):
        cur_path = os.path.dirname(__file__)
        dll_path = os.path.join(cur_path, "")
        self.std_dll = ctypes.cdll.LoadLibrary(os.path.join(dll_path, "./stdf_ctype.dll"))
        """
        init func
        """
        "生成类"
        self._detector_new_func = self.std_dll.NewStdf
        self._detector_new_func.restype = ctypes.c_void_p
        "获取失效信息"
        self._get_error_message = self.std_dll.GetErrorMessage
        self._get_error_message.argtypes = [ctypes.c_void_p]
        self._get_error_message.restype = ctypes.c_char_p
        "载入成功STDF后的types"
        self._get_stdf_types = self.std_dll.GetStdfTypes
        self._get_stdf_types.argtypes = [ctypes.c_void_p]
        self._get_stdf_types.restype = ctypes.c_char_p
        "更改文件是否产生表头"
        self._generator_file_head = self.std_dll.ChangeFileHead
        self._generator_file_head.argtypes = [ctypes.c_void_p, ctypes.c_bool]
        self._generator_file_head.restype = ctypes.c_bool
        "执行STDF TYPE文件生成"
        self._exec_stdf_generator = self.std_dll.ExecStdf
        self._exec_stdf_generator.argtypes = [ctypes.c_void_p, ctypes.c_int, ctypes.c_char_p]
        self._exec_stdf_generator.restype = ctypes.c_int
        "执行STDF CSV数据文件生成"
        self._exec_stdf_to_csv_rawdata = self.std_dll.ExecStdfToCsv
        self._exec_stdf_to_csv_rawdata.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_char_p]
        self._exec_stdf_to_csv_rawdata.restype = ctypes.c_bool
        "执行STDF CSV_SQL数据文件生成"
        self._exec_stdf_to_csv_sql = self.std_dll.ExecStdfToCsvSql
        self._exec_stdf_to_csv_sql.argtypes = [ctypes.c_void_p, ctypes.c_wchar_p, ctypes.c_char_p, ctypes.c_char_p]
        self._exec_stdf_to_csv_sql.restype = ctypes.c_bool
        "清空stdf缓存"
        self._delete_stdf_func = self.std_dll.DeleteStdf
        self._delete_stdf_func.argtypes = [ctypes.c_void_p]
        self._delete_stdf_func.restype = ctypes.c_bool

    def init(self):
        """
        初始化类
        """
        if self.stdf:
            self._delete_stdf_func(self.stdf)
        self.stdf = self._detector_new_func()

    def clear(self):
        if self.stdf:
            self._delete_stdf_func(self.stdf)
            self.stdf = None

    def __del__(self):
        if self.stdf:
            self._delete_stdf_func(self.stdf)
            self.stdf = None
        win32api.FreeLibrary(self.std_dll._handle)
        del self.std_dll

    def get_err_message(self) -> str:
        """
        获取dll中的当前报错信息
        :return:
        """
        if self.stdf is None:
            raise Exception("no init")
        return self.char_to_string(self._get_error_message(self.stdf))

    def set_stdf_generator_head(self, boolean: bool) -> bool:
        """
        设置解析出来的csv是否需要表头, sqlserver bulk insert 是不能有表头的
        :param boolean:
        :return:
        """
        return self._generator_file_head(self.stdf, ctypes.c_bool(boolean))

    def get_stdf_types(self) -> str:
        """
        获取stdf解析后的所有type数据
        :return: "1,3,4,5"  -->  对着 TYPE_DICT 看
        """
        if self.stdf is None:
            raise Exception("no init")
        if not self.import_status:
            return ''
        return self.char_to_string(self._get_stdf_types(self.stdf))

    def exec_stdf_to_csv(self, stdf_type: int, save_path: str) -> int:
        """
        将各个type的数据导出为csv
        :param stdf_type: 1: FAR
        :param save_path:
        :return:
        """
        if not isinstance(stdf_type, int):
            raise Exception("type 必须是int类型")
        resp = self._exec_stdf_generator(self.stdf, stdf_type, self.string_to_char(save_path))
        # print(self.STDF_RETURN[resp])
        return self.STDF_RESULT[resp]

    def exec_stdf_to_csv_rawdata(self, stdf_file: str, save_file: str) -> bool:
        """
        将数据导出为rawdata csv格式
        :param save_file:
        :param stdf_file:
        :return:
        """
        resp = self._exec_stdf_to_csv_rawdata(self.stdf, self.string_to_wchar(stdf_file),
                                              self.string_to_char(save_file))
        self.import_status = True if resp else False
        return resp

    def exec_stdf_to_sql_rawdata(self, stdf_file: str, save_file: str, save_limit: str):
        resp = self._exec_stdf_to_csv_sql(self.stdf, self.string_to_wchar(stdf_file), self.string_to_char(save_file),
                                          self.string_to_char(save_limit))
        self.import_status = True if resp else False
        return resp

    @staticmethod
    def string_to_char(_string: str) -> ctypes.Array:
        return ctypes.create_string_buffer(bytes(_string, encoding='utf8'))

    @staticmethod
    def string_to_wchar(_string: str):
        return ctypes.create_unicode_buffer(_string)

    @staticmethod
    def char_to_string(c_char: ctypes.c_char_p) -> str:
        temp_bytes = ctypes.string_at(c_char)
        return temp_bytes.decode("utf-8")

    @staticmethod
    def generator_a_z():
        length = 1
        while length:
            for letters in itertools.product(string.ascii_uppercase, repeat=length):
                yield ''.join(letters)
            length += 1


if __name__ == '__main__':
    filepath = r"E:\文档目录\N61094_V1P2_16S_SQN5L03-A5_24Apr2022_1517.std"
    stdf = LinkStdf()
    stdf.init()
    raw = os.path.join(r'E:\文档目录', 'test.csv')
    limit = os.path.join(r'E:\文档目录', 'limit.csv')
    print(stdf.exec_stdf_to_sql_rawdata(filepath, raw, limit))
